﻿/*
  Copyright © Alexander G. Bykin, Russia 2009-2010
  This source is subject to the Microsoft Public License (Ms-PL).
  Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
  All other rights reserved.
*/

namespace System.Windows.Controls
{
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Windows.Controls.Data;
    using System.Windows.Controls.Primitives;
    using System.Windows.Input;
    using System.Windows.Media.Imaging;


    /// <summary>
    /// Customizable DomainDataSource Sort descriptors.
    /// </summary>
    /// <QualityBand>Stable</QualityBand>
    [TemplatePart(Name = "btnAddSort", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "btnDeleteSort", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "btnClearSort", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "btnApply", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "btnCancel", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "dgcSortPropertyPath", Type = typeof(DataGridColumn))]
    [TemplatePart(Name = "dgcSortDirection", Type = typeof(DataGridColumn))]
    [TemplatePart(Name = "dgSort", Type = typeof(DataGrid))]
    [TemplatePart(Name = "deleteRowCmd", Type = typeof(DynaCommand))]
    [TemplatePart(Name = "deleteRowToolTip", Type = typeof(DynaObject))]
    [TemplatePart(Name = "switchFieldsComboOrderByCmd", Type = typeof(DynaCommand))]
    [TemplatePart(Name = "switchFieldsComboOrderByToolTip", Type = typeof(DynaObject))]
    [TemplatePart(Name = "fieldsComboOrderByImage", Type = typeof(DynaObject))]
    public class DataSort : Control
    {
        #region Constants

        /// <summary>
        /// The default order to use when there is no <see cref="DisplayAttribute.Order"/>
        /// value available for the property.
        /// </summary>
        /// <remarks>
        /// The value of 10000 is a standard default value, allowing
        /// some properties to be ordered at the beginning and some at the end.
        /// </remarks>
        private const int UnspecifiedOrder = 10000;

        private const string DATASORT_elementButtonAddSort = "btnAddSort";
        private const string DATASORT_elementButtonDeleteSort = "btnDeleteSort";
        private const string DATASORT_elementButtonClearSort = "btnClearSort";
        private const string DATASORT_elementButtonApply = "btnApply";
        private const string DATASORT_elementButtonCancel = "btnCancel";
        private const string DATASORT_elementDataGridColumnSortPropertyPath = "dgcSortPropertyPath";
        private const string DATASORT_elementDataGridColumnSortPropertyPathHeader = "dgcSortPropertyPathHeader";
        private const string DATASORT_elementDataGridColumnSortDirection = "dgcSortDirection";
        private const string DATASORT_elementDataGridSort = "dgSort";
        private const string DATASORT_elementDeleteRowCmd = "deleteRowCmd";
        private const string DATASORT_elementDeleteRowToolTip = "deleteRowToolTip";
        private const string DATASORT_elementSwitchFieldsComboOrderByCmd = "switchFieldsComboOrderByCmd";
        private const string DATASORT_elementSwitchFieldsComboOrderByToolTip = "switchFieldsComboOrderByToolTip";
        private const string DATASORT_elementFieldsComboOrderByImage = "fieldsComboOrderByImage";


        private const string DATASORT_DefaultButtonAddSortTooltip = "Add Sort";
        private const string DATASORT_DefaultButtonDeleteSortTooltip = "Remove Sort";
        private const string DATASORT_DefaultButtonClearSortTooltip = "Clear Sort";
        private const string DATASORT_DefaultButtonApplyContent = "Apply";
        private const string DATASORT_DefaultButtonCancelContent = "Cancel";
        private const string DATASORT_DefaultButtonApplyTooltip = "Apply filters";
        private const string DATASORT_DefaultButtonCancelTooltip = "Cancel filters";
        private const string DATASORT_DefaultDataGridColumnSortPropertyPath = "Field name";
        private const string DATASORT_DefaultDataGridColumnSortDirection = "Direction";
        private const string DATASORT_DefaultButtonSwitchFieldsComboOrderByTooltip = "Change 'Field name' combobox sort order";

        #endregion

        #region Dependency Properties

        #region DependencyProperty DomainEntityFieldCollection

        /// <summary>
        /// Identifies the DomainEntityFieldCollection dependency property.
        /// </summary>
        public static readonly DependencyProperty DomainEntityFieldCollectionProperty =
            DependencyProperty.Register(
                "DomainEntityFieldCollection",
                typeof(DomainEntityFieldCollection),
                typeof(DataSort),
                new PropertyMetadata(new DomainEntityFieldCollection(), OnDomainEntityFieldCollectionPropertyChanged));

        /// <summary>
        /// DomainEntityFieldCollection property changed handler.
        /// </summary>
        /// <param name="d">DataSort that changed its DomainEntityFieldCollection value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnDomainEntityFieldCollectionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataSort control = d as DataSort;
            if (control == null)
            {
                return;
            }

            //control.DomainEntityFieldCollection = e.NewValue as DomainEntityFieldCollection;
            control.RefreshListOfDomainEntityFields();
            control.RefreshSortItems();
        }

        #endregion

        #region DependencyProperty SortDirectionLocalizationCollection

        /// <summary>
        /// Identifies the SortDirectionLocalizationCollection dependency property.
        /// </summary>
        public static readonly DependencyProperty SortDirectionLocalizationCollectionProperty =
            DependencyProperty.Register(
                "SortDirectionLocalizationCollection",
                typeof(SortDirectionLocalizationCollection),
                typeof(DataSort),
                new PropertyMetadata(OnSortDirectionLocalizationCollectionPropertyChanged));

        /// <summary>
        /// SortDirectionLocalizationCollection property changed handler.
        /// </summary>
        /// <param name="d">DataSort that changed its SortDirectionLocalizationCollection value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnSortDirectionLocalizationCollectionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataSort control = d as DataSort;
            if (control == null)
            {
                return;
            }

            //control.SortDirectionLocalizationCollection = e.NewValue as SortDirectionLocalizationCollection;

        }

        #endregion

        #region DependencyProperty ButtonAddSortTooltip

        /// <summary>
        /// Identifies the ButtonAddSortTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonAddSortTooltipProperty =
            DependencyProperty.Register(
                "ButtonAddSortTooltip",
                typeof(string),
                typeof(DataSort),
                new PropertyMetadata(DATASORT_DefaultButtonAddSortTooltip, OnButtonAddSortTooltipPropertyChanged));

        /// <summary>
        /// ButtonAddSortTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataSort that changed its ButtonAddSortTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonAddSortTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataSort control = d as DataSort;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnAddSort != null &&
                !string.IsNullOrEmpty(newValue))
            {
                ToolTipService.SetToolTip(control.btnAddSort, newValue);
            }
        }

        #endregion

        #region DependencyProperty ButtonDeleteSortTooltip

        /// <summary>
        /// Identifies the ButtonDeleteSortTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonDeleteSortTooltipProperty =
            DependencyProperty.Register(
                "ButtonDeleteSortTooltip",
                typeof(string),
                typeof(DataSort),
                new PropertyMetadata(DATASORT_DefaultButtonDeleteSortTooltip, OnButtonDeleteSortTooltipPropertyChanged));

        /// <summary>
        /// ButtonDeleteSortTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataSort that changed its ButtonDeleteSortTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonDeleteSortTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataSort control = d as DataSort;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnDeleteSort != null &&
                !string.IsNullOrEmpty(newValue))
            {
                ToolTipService.SetToolTip(control.btnDeleteSort, newValue);
                if (control.dgSort != null)
                  ((DynaObject)control.dgSort.Resources[DATASORT_elementDeleteRowToolTip]).Value = newValue;
            }
        }

        #endregion

        #region DependencyProperty ButtonClearSortTooltip

        /// <summary>
        /// Identifies the ButtonClearSortTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonClearSortTooltipProperty =
            DependencyProperty.Register(
                "ButtonClearSortTooltip",
                typeof(string),
                typeof(DataSort),
                new PropertyMetadata(DATASORT_DefaultButtonClearSortTooltip, OnButtonClearSortTooltipPropertyChanged));

        /// <summary>
        /// ButtonClearSortTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataSort that changed its ButtonClearSortTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonClearSortTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataSort control = d as DataSort;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnClearSort != null &&
                !string.IsNullOrEmpty(newValue))
            {
                ToolTipService.SetToolTip(control.btnClearSort, newValue);
            }
        }

        #endregion

        #region DependencyProperty ButtonApplyContent

        /// <summary>
        /// Identifies the ButtonApplyContent dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonApplyContentProperty =
            DependencyProperty.Register(
                "ButtonApplyContent",
                typeof(string),
                typeof(DataSort),
                new PropertyMetadata(DATASORT_DefaultButtonApplyContent, OnButtonApplyContentPropertyChanged));

        /// <summary>
        /// ButtonApplyContent property changed handler.
        /// </summary>
        /// <param name="d">DataSort that changed its ButtonApplyContent value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonApplyContentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataSort control = d as DataSort;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnApply != null &&
                !string.IsNullOrEmpty(newValue))
            {
                control.btnApply.Content = newValue;
            }
        }

        #endregion

        #region DependencyProperty ButtonCancelContent

        /// <summary>
        /// Identifies the ButtonCancelContent dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonCancelContentProperty =
            DependencyProperty.Register(
                "ButtonCancelContent",
                typeof(string),
                typeof(DataSort),
                new PropertyMetadata(DATASORT_DefaultButtonCancelContent, OnButtonCancelContentPropertyChanged));

        /// <summary>
        /// ButtonCancelContent property changed handler.
        /// </summary>
        /// <param name="d">DataSort that changed its ButtonCancelContent value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonCancelContentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataSort control = d as DataSort;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnCancel != null &&
                !string.IsNullOrEmpty(newValue))
            {
                control.btnCancel.Content = newValue;
            }
        }

        #endregion

        #region DependencyProperty ButtonApplyTooltip

        /// <summary>
        /// Identifies the ButtonApplyTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonApplyTooltipProperty =
            DependencyProperty.Register(
                "ButtonApplyTooltip",
                typeof(string),
                typeof(DataSort),
                new PropertyMetadata(DATASORT_DefaultButtonApplyTooltip, OnButtonApplyTooltipPropertyChanged));

        /// <summary>
        /// ButtonApplyTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataSort that changed its ButtonApplyTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonApplyTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataSort control = d as DataSort;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnApply != null &&
                !string.IsNullOrEmpty(newValue))
            {
                ToolTipService.SetToolTip(control.btnApply, newValue);
            }
        }

        #endregion

        #region DependencyProperty ButtonCancelTooltip

        /// <summary>
        /// Identifies the ButtonCancelTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonCancelTooltipProperty =
            DependencyProperty.Register(
                "ButtonCancelTooltip",
                typeof(string),
                typeof(DataSort),
                new PropertyMetadata(DATASORT_DefaultButtonCancelTooltip, OnButtonCancelTooltipPropertyChanged));

        /// <summary>
        /// ButtonCancelTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataSort that changed its ButtonCancelTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonCancelTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataSort control = d as DataSort;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.btnCancel != null &&
                !string.IsNullOrEmpty(newValue))
            {
                ToolTipService.SetToolTip(control.btnCancel, newValue);
            }
        }

        #endregion

        #region DependencyProperty ButtonSwitchFieldsComboOrderByTooltip

        /// <summary>
        /// Identifies the ButtonSwitchFieldsComboOrderByTooltip dependency property.
        /// </summary>
        public static readonly DependencyProperty ButtonSwitchFieldsComboOrderByTooltipProperty =
            DependencyProperty.Register(
                "ButtonSwitchFieldsComboOrderByTooltip",
                typeof(string),
                typeof(DataSort),
                new PropertyMetadata(DATASORT_DefaultButtonSwitchFieldsComboOrderByTooltip, OnButtonSwitchFieldsComboOrderByTooltipPropertyChanged));

        /// <summary>
        /// ButtonSwitchFieldsComboOrderByTooltip property changed handler.
        /// </summary>
        /// <param name="d">DataSort that changed its ButtonSwitchFieldsComboOrderByTooltip value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnButtonSwitchFieldsComboOrderByTooltipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
          DataSort control = d as DataSort;
          if (control == null) return;

          string newValue = e.NewValue as string;

          if (control.dgSort != null && !string.IsNullOrEmpty(newValue))
            ((DynaObject)control.dgSort.Resources[DATASORT_elementSwitchFieldsComboOrderByToolTip]).Value = newValue;
        }

        #endregion

        #region DependencyProperty DomainDataSource

        /// <summary>
        /// Identifies the DomainDataSource dependency property.
        /// </summary>
        public static readonly DependencyProperty DomainDataSourceProperty =
            DependencyProperty.Register(
                "DomainDataSource",
                typeof(DomainDataSource),
                typeof(DataSort),
                new PropertyMetadata(OnDomainDataSourcePropertyChanged));

        /// <summary>
        /// DomainDataSource property changed handler.
        /// </summary>
        /// <param name="d">DataSort that changed its DomainDataSource value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnDomainDataSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataSort control = d as DataSort;
            if (control == null)
            {
                return;
            }

            if (e.OldValue != null) {
              var old = e.OldValue as DomainDataSource;
              if (old != null)
                old.FilterDescriptors.CollectionChanged -= control.SortDescriptorsChanged;
            }
            control.RefreshSortItems();
            if (control.DomainDataSource != null)
              control.DomainDataSource.SortDescriptors.CollectionChanged += control.SortDescriptorsChanged;
        }

        void RefreshSortItems()
        {
          DomainDataSource.GetDDSSortDescriptorsCopy(DomainEntityFieldCollection.ToList(), dataGridSortItems);
          RefreshControls();
        }

        void SortDescriptorsChanged(object sender, Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
          // DomainDataSource.SortDescriptors are changed by external control, DataGrid for example
          if (!changingSortDescrs && ListenSortDescriptorsChanges)
            RefreshSortItems();
        }

        #endregion

        #region DependencyProperty ListenSortDescriptorsChangesProperty

        /// <summary>
        /// Identifies the ListenSortDescriptorsChangesProperty dependency property.
        /// </summary>
        public static readonly DependencyProperty ListenSortDescriptorsChangesProperty =
            DependencyProperty.Register(
                "ListenSortDescriptorsChangesProperty",
                typeof(bool),
                typeof(DataSort),
                new PropertyMetadata(false/*defaultValue*/, OnListenSortDescriptorsChangesPropertyChanged));

        /// <summary>
        /// ListenSortDescriptorsChangesProperty changed handler.
        /// </summary>
        /// <param name="d">DataSort that changed its ListenSortDescriptorsChangesProperty value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnListenSortDescriptorsChangesPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
          DataSort control = d as DataSort;
          if (control == null) {
            return;
          }
          if (e.NewValue != null) { }
        }

        #endregion

        #region DependencyProperty SortPropertyPathHeader

        /// <summary>
        /// Identifies the SortPropertyPathHeader dependency property.
        /// </summary>
        public static readonly DependencyProperty SortPropertyPathHeaderProperty =
            DependencyProperty.Register(
                "SortPropertyPathHeader",
                typeof(string),
                typeof(DataSort),
                new PropertyMetadata(DATASORT_DefaultDataGridColumnSortPropertyPath, OnSortPropertyPathHeaderPropertyChanged));

        /// <summary>
        /// SortPropertyPathHeader property changed handler.
        /// </summary>
        /// <param name="d">DataSort that changed its SortPropertyPathHeader value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnSortPropertyPathHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataSort control = d as DataSort;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.dgSort != null &&
                !string.IsNullOrEmpty(newValue))
            {
              ((DynaString)control.dgSort.Resources[DATASORT_elementDataGridColumnSortPropertyPathHeader]).Value = newValue;
            }
        }

        #endregion

        #region DependencyProperty SortDirectionHeader

        /// <summary>
        /// Identifies the SortDirectionHeader dependency property.
        /// </summary>
        public static readonly DependencyProperty SortDirectionHeaderProperty =
            DependencyProperty.Register(
                "SortDirectionHeader",
                typeof(string),
                typeof(DataSort),
                new PropertyMetadata(DATASORT_DefaultDataGridColumnSortDirection, OnSortDirectionHeaderPropertyChanged));

        /// <summary>
        /// SortDirectionHeader property changed handler.
        /// </summary>
        /// <param name="d">DataSort that changed its SortDirectionHeader value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnSortDirectionHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataSort control = d as DataSort;
            if (control == null)
            {
                return;
            }

            string newValue = e.NewValue as string;

            if (control.dgcSortDirection != null &&
                !string.IsNullOrEmpty(newValue))
            {
                control.dgcSortDirection.Header = newValue;
            }
        }

        #endregion

        #region DependencyProperty ExcludeFieldList

        /// <summary>
        /// Identifies the ExcludeFieldList dependency property.
        /// </summary>
        public static readonly DependencyProperty ExcludeFieldListProperty =
            DependencyProperty.Register(
            "ExcludeFieldList",
            typeof(string),
            typeof(DataSort),
            new PropertyMetadata(string.Empty, OnExcludeFieldListPropertyChanged));

        /// <summary>
        /// ExcludeFieldList property changed handler.
        /// </summary>
        /// <param name="d">DataSort that changed its ExcludeFieldList value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnExcludeFieldListPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataSort control = d as DataSort;
            if (control == null)
            {
                return;
            }

            //control.ExcludeFieldList = (e.NewValue as string);
        }

        #endregion

        #region DependencyProperty IncludeFieldList

        /// <summary>
        /// Identifies the IncludeFieldList dependency property.
        /// </summary>
        public static readonly DependencyProperty IncludeFieldListProperty =
            DependencyProperty.Register(
            "IncludeFieldList",
            typeof(string),
            typeof(DataSort),
            new PropertyMetadata(string.Empty, OnIncludeFieldListPropertyChanged));

        /// <summary>
        /// IncludeFieldList property changed handler.
        /// </summary>
        /// <param name="d">DataSort that changed its IncludeFieldList value.</param>
        /// <param name="e">The DependencyPropertyChangedEventArgs for this event.</param>
        private static void OnIncludeFieldListPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataSort control = d as DataSort;
            if (control == null)
            {
                return;
            }

            //control.IncludeFieldList = (e.NewValue as string);
        }

        #endregion

        #region DependencyProperty EntityFieldsComboOrderBy

        public static readonly DependencyProperty EntityFieldsComboOrderByProperty =
            DependencyProperty.Register(
            "EntityFieldsComboOrderBy",
            typeof(EntityFieldsOrder),
            typeof(DataSort),
            new PropertyMetadata(EntityFieldsOrder.Alphabetical, OnEntityFieldsComboOrderByPropertyChanged));

        public EntityFieldsOrder EntityFieldsComboOrderBy
        {
          get { return (EntityFieldsOrder)GetValue(EntityFieldsComboOrderByProperty); }
          set { SetValue(EntityFieldsComboOrderByProperty, value); }
        }

        private static void OnEntityFieldsComboOrderByPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
          DataSort control = d as DataSort;
          if (control == null) return;
          control.SetFieldsComboOrderByImage();
          control.RefreshListOfDomainEntityFields();
        }

        private void SetFieldsComboOrderByImage()
        {
          switch (EntityFieldsComboOrderBy) {
            case EntityFieldsOrder.Alphabetical:
              var img = new BitmapImage(new Uri(@"/System.Windows.Controls.Data.RIADataFilter.Control;component/Images/Alphabet.png", UriKind.Relative));
              ((DynaObject)this.dgSort.Resources[DATASORT_elementFieldsComboOrderByImage]).Value = img;
              break;
            case EntityFieldsOrder.DisplayOrder:
              img = new BitmapImage(new Uri(@"/System.Windows.Controls.Data.RIADataFilter.Control;component/Images/Numbering.png", UriKind.Relative));
              ((DynaObject)this.dgSort.Resources[DATASORT_elementFieldsComboOrderByImage]).Value = img;
              break;
          }
        }

        #endregion

        #endregion

        #region Private Properties

        #region Private Property dataGridSortItems

        private List<DataGridSortItem> dataGridSortItems { get; set; }

        #endregion

        #region Private Property listOfSortDirectionNames

        /// <summary>
        /// Holds the list of SortDirection names.
        /// </summary>
        private IList<string> listOfSortDirectionNames { get; set; }

        #endregion

        #region Private Property btnAddSort

        /// <summary>
        /// Private accessor to btnAddSort Button.
        /// </summary>
        private ButtonBase btnAddSort { get; set; }

        #endregion

        #region Private Property btnDeleteSort

        /// <summary>
        /// Private accessor to btnDeleteSort Button.
        /// </summary>
        private ButtonBase btnDeleteSort { get; set; }
        private ICommand deleteCmd { get; set; }

        #endregion

        #region Private Property btnClearSort

        /// <summary>
        /// Private accessor to btnClearSort Button.
        /// </summary>
        private ButtonBase btnClearSort { get; set; }
        private ICommand clearCmd { get; set; }

        #endregion

        #region Private Property btnApply

        /// <summary>
        /// Private accessor to btnApply Button.
        /// </summary>
        private ButtonBase btnApply { get; set; }
        private ICommand applyCmd { get; set; }

        #endregion

        #region Private Property btnCancel

        /// <summary>
        /// Private accessor to btnCancel Button.
        /// </summary>
        private ButtonBase btnCancel { get; set; }
        private ICommand cancelCmd { get; set; }

        #endregion

        #region Private Property dgSort

        /// <summary>
        /// Private accessor to dgSort DataGrid.
        /// </summary>
        private DataGrid dgSort { get; set; }

        #endregion

        #region Private Property dgcSortPropertyPath

        /// <summary>
        /// Private accessor to dgcSortPropertyPath DataGrid Column.
        /// </summary>
        private DataGridColumn dgcSortPropertyPath { get; set; }

        #endregion

        #region Private Property dgcSortDirection

        /// <summary>
        /// Private accessor to dgcSortDirection DataGrid Column.
        /// </summary>
        private DataGridColumn dgcSortDirection { get; set; }

        #endregion

        #region Private Property changingSortDescrs

        private bool changingSortDescrs = false;

        #endregion

        #region Private Property deleteRowCmd

        private ICommand deleteRowCmd { get; set; }

        #endregion

        #region Private Property switchFieldsComboOrderByCmd

        private ICommand switchFieldsComboOrderByCmd { get; set; }

        #endregion

        #endregion

        #region Public Properties

        #region Public Property SortDirectionLocalizationCollection

        public SortDirectionLocalizationCollection SortDirectionLocalizationCollection
        {
            get
            {
                return GetValue(SortDirectionLocalizationCollectionProperty) as SortDirectionLocalizationCollection;
            }
            set
            {
                SetValue(SortDirectionLocalizationCollectionProperty, value);
            }
        }

        #endregion

        #region Public Property DomainEntityFieldCollection

        public DomainEntityFieldCollection DomainEntityFieldCollection
        {
            get
            {
                return GetValue(DomainEntityFieldCollectionProperty) as DomainEntityFieldCollection;
            }
            set
            {
                SetValue(DomainEntityFieldCollectionProperty, value);
            }
        }

        #endregion

        #region Public Property ListOfDomainEntityFields

        /// <summary>
        /// Gets the list of DomainEntityField.
        /// </summary>
        public List<DomainEntityField> ListOfDomainEntityFields { get; private set; }

        #endregion

        #region Public Property ListOfSortDirectionNames

        public IList<string> ListOfSortDirectionNames
        {
            get
            {
                if (this.listOfSortDirectionNames == null)
                {
                    this.listOfSortDirectionNames = Utilities.GetListOfSortDirectionNames(this.SortDirectionLocalizationCollection);
                }
                return this.listOfSortDirectionNames;
            }
        }

        #endregion

        #region Public Property ButtonAddSortTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the AddSort Button.
        /// </summary>
        public string ButtonAddSortTooltip
        {
            get
            {
                return this.GetValue(ButtonAddSortTooltipProperty) as string;
            }

            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonAddSortTooltipProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ButtonDeleteSortTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the DeleteSort Button.
        /// </summary>
        public string ButtonDeleteSortTooltip
        {
            get
            {
                return this.GetValue(ButtonDeleteSortTooltipProperty) as string;
            }

            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonDeleteSortTooltipProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ButtonClearSortTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the ClearSort Button.
        /// </summary>
        public string ButtonClearSortTooltip
        {
            get
            {
                return this.GetValue(ButtonClearSortTooltipProperty) as string;
            }

            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonClearSortTooltipProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ButtonApplyTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the Apply Button.
        /// </summary>
        public string ButtonApplyTooltip
        {
            get
            {
                return this.GetValue(ButtonApplyTooltipProperty) as string;
            }

            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonApplyTooltipProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ButtonCancelTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the Cancel Button.
        /// </summary>
        public string ButtonCancelTooltip
        {
            get
            {
                return this.GetValue(ButtonCancelTooltipProperty) as string;
            }

            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonCancelTooltipProperty, value);
                }
            }
        }

        #endregion

        #region Property ButtonSwitchFieldsComboOrderByTooltip

        /// <summary>
        /// Gets or sets the Tooltip of the SwitchFieldsComboOrderBy Button.
        /// </summary>
        public string ButtonSwitchFieldsComboOrderByTooltip
        {
          get
          {
            return this.GetValue(ButtonSwitchFieldsComboOrderByTooltipProperty) as string;
          }

          set
          {
            if (!string.IsNullOrEmpty(value))
            {
              this.SetValue(ButtonSwitchFieldsComboOrderByTooltipProperty, value);
            }
          }
        }

        #endregion

        #region Public Property ButtonApplyContent

        /// <summary>
        /// Gets or sets the Content of the Apply Button.
        /// </summary>
        public string ButtonApplyContent
        {
            get
            {
                return this.GetValue(ButtonApplyContentProperty) as string;
            }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonApplyContentProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ButtonCancelContent

        /// <summary>
        /// Gets or sets the Content of the Cancel button.
        /// </summary>
        public string ButtonCancelContent
        {
            get
            {
                return this.GetValue(ButtonCancelContentProperty) as string;
            }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(ButtonCancelContentProperty, value);
                }
            }
        }

        #endregion

        #region Public Property DomainDataSource

        /// <summary>
        /// Gets or sets a DomainDataSource.
        /// </summary>
        public DomainDataSource DomainDataSource
        {
            get
            {
                return this.GetValue(DomainDataSourceProperty) as DomainDataSource;
            }
            set
            {
                this.SetValue(DomainDataSourceProperty, value);
            }
        }

        #endregion

        #region Public Property ListenSortDescriptorsChanges

        [DefaultValue(false)]
        public bool ListenSortDescriptorsChanges
        {
          get { return (bool)this.GetValue(ListenSortDescriptorsChangesProperty); }
          set { this.SetValue(ListenSortDescriptorsChangesProperty, value); }
        }

        #endregion

        #region Public Property SortPropertyPathHeader

        /// <summary>
        /// Gets or sets the Header of the SortPropertyPath.
        /// </summary>
        public string SortPropertyPathHeader
        {
            get
            {
                return this.GetValue(SortPropertyPathHeaderProperty) as string;
            }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(SortPropertyPathHeaderProperty, value);
                }
            }
        }

        #endregion

        #region Public Property SortDirectionHeader

        /// <summary>
        /// Gets or sets the Header of the SortDirection.
        /// </summary>
        public string SortDirectionHeader
        {
            get
            {
                return this.GetValue(SortDirectionHeaderProperty) as string;
            }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    this.SetValue(SortDirectionHeaderProperty, value);
                }
            }
        }

        #endregion

        #region Public Property ExcludeFieldList

        /// <summary>
        /// Gets or Sets the Field list than must be Ignored when filling field list for ComboBox
        /// </summary>
        public string ExcludeFieldList
        {
            get
            {
                return (string)GetValue(ExcludeFieldListProperty);
            }
            set
            {
                SetValue(ExcludeFieldListProperty, value);
            }
        }

        #endregion

        #region Public Property IncludeFieldList

        /// <summary>
        /// Gets or Sets the Field list than must be Added when filling field list for ComboBox
        /// </summary>
        public string IncludeFieldList
        {
            get
            {
                return (string)GetValue(IncludeFieldListProperty);
            }
            set
            {
                SetValue(IncludeFieldListProperty, value);
            }
        }

        #endregion

        #region Public Property OnApplyButtonBeforeClick

        public event EventHandler OnApplyButtonBeforeClick;

        #endregion

        #region Public Property OnCancelButtonBeforeClick

        public event EventHandler OnCancelButtonBeforeClick;

        #endregion

        #region Public Property OnApplyButtonAfterClick

        public event EventHandler OnApplyButtonAfterClick;

        #endregion

        #region Public Property OnCancelButtonAfterClick

        public event EventHandler OnCancelButtonAfterClick;

        #endregion

        #region Public Property OnCanCancel

        public event CanCancelEventHandler OnCanCancel;

        #endregion

        #region Public Property CellEditorPrepared

        public event EventHandler CellEditorPrepared;

        #endregion

        #endregion

        #region Constructors

        public DataSort()
        {
            DefaultStyleKey = typeof(DataSort);
            this.dataGridSortItems = new List<DataGridSortItem>();
            this.LayoutUpdated += OnDataSortLayoutUpdated;
            applyCmd  = new DelegateCommand<object>(ApplyFilters , CanApplyFilters );
            cancelCmd = new DelegateCommand<object>(CancelFilters, CanCancelFilters);
            deleteCmd = new DelegateCommand<object>(DeleteSortItem, CanDeleteSortItem);
            clearCmd  = new DelegateCommand<object>(ClearSortItem, CanClearSortItem);
            deleteRowCmd = new DelegateCommand<object>(AsyncDeleteRowSortItem, CanDeleteRowSortItem);
            switchFieldsComboOrderByCmd = new DelegateCommand<object>(SwitchFieldsComboOrderBy, CanSwitchFieldsComboOrderBy);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            #region Button AddSort

            if (this.btnAddSort != null)
            {
                this.btnAddSort.Click -= new RoutedEventHandler(this.OnButtonAddSortClick);
            }

            this.btnAddSort = GetTemplateChild(DATASORT_elementButtonAddSort) as ButtonBase;

            if (this.btnAddSort != null)
            {
                this.btnAddSort.Click += new RoutedEventHandler(this.OnButtonAddSortClick);

                ToolTipService.SetToolTip(this.btnAddSort, this.ButtonAddSortTooltip);

                /*if (this.AddSortButtonStyle != null)
                {
                    this._addSortButton.SetBinding(ButtonBase.StyleProperty, new Binding("AddSortButtonStyle") { Source = this });
                }*/
            }

            #endregion

            #region Button DeleteSort

            if (this.btnDeleteSort != null)
            {
                this.btnDeleteSort.Command = null;
            }

            this.btnDeleteSort = GetTemplateChild(DATASORT_elementButtonDeleteSort) as ButtonBase;

            if (this.btnDeleteSort != null)
            {
                this.btnDeleteSort.Command = deleteCmd;

                ToolTipService.SetToolTip(this.btnDeleteSort, this.ButtonDeleteSortTooltip);

                /*if (this.DeleteSortButtonStyle != null)
                {
                    this._deleteSortButton.SetBinding(ButtonBase.StyleProperty, new Binding("DeleteSortButtonStyle") { Source = this });
                }*/
            }

            #endregion

            #region Button ClearSort

            if (this.btnClearSort != null)
            {
                this.btnClearSort.Command = null;
            }

            this.btnClearSort = GetTemplateChild(DATASORT_elementButtonClearSort) as ButtonBase;

            if (this.btnClearSort != null)
            {
                this.btnClearSort.Command = clearCmd;

                ToolTipService.SetToolTip(this.btnClearSort, this.ButtonClearSortTooltip);

                /*if (this.ClearSortButtonStyle != null)
                {
                    this._clearSortButton.SetBinding(ButtonBase.StyleProperty, new Binding("ClearSortButtonStyle") { Source = this });
                }*/
            }

            #endregion

            #region Button Apply

            if (this.btnApply != null)
            {
                this.btnApply.Command = null;
            }

            this.btnApply = GetTemplateChild(DATASORT_elementButtonApply) as ButtonBase;

            if (this.btnApply != null)
            {
                this.btnApply.Command = applyCmd;
                this.btnApply.Content = this.ButtonApplyContent;

                ToolTipService.SetToolTip(this.btnApply, this.ButtonApplyTooltip);

                /*if (this.AddRecordButtonStyle != null)
                                {
                                    this._addRecordButton.SetBinding(ButtonBase.StyleProperty, new Binding("CancelButtonStyle") { Source = this });
                                }*/
            }

            #endregion

            #region Button Cancel

            if (this.btnCancel != null)
            {
                this.btnCancel.Command = null;
            }

            this.btnCancel = GetTemplateChild(DATASORT_elementButtonCancel) as ButtonBase;

            if (this.btnCancel != null)
            {
                this.btnCancel.Command = cancelCmd;
                this.btnCancel.Content = this.ButtonCancelContent;

                ToolTipService.SetToolTip(this.btnCancel, this.ButtonCancelTooltip);

                /*if (this.AddRecordButtonStyle != null)
                                {
                                    this._addRecordButton.SetBinding(ButtonBase.StyleProperty, new Binding("CancelButtonStyle") { Source = this });
                                }*/
            }

            #endregion

            #region DataGridColumn SortPropertyPath

            this.dgcSortPropertyPath = GetTemplateChild(DATASORT_elementDataGridColumnSortPropertyPath) as DataGridColumn;

            if (this.dgcSortPropertyPath != null) { }

            #endregion

            #region DataGridColumn SortDirection

            this.dgcSortDirection = GetTemplateChild(DATASORT_elementDataGridColumnSortDirection) as DataGridColumn;

            if (this.dgcSortDirection != null)
            {
                this.dgcSortDirection.Header = this.SortDirectionHeader;
            }

            #endregion

            #region DataGrid Sort

            if (this.dgSort != null)
            {
                this.dgSort.PreparingCellForEdit -= OnDataGridSortPreparingCellForEdit;
                this.dgSort.SelectionChanged     -= dgSort_SelectionChanged;
                this.dgSort.CurrentCellChanged   -= dgSort_CurrentCellChanged;
                ((DynaCommand)this.dgSort.Resources[DATASORT_elementDeleteRowCmd]).Value = null;
                ((DynaObject )this.dgSort.Resources[DATASORT_elementDeleteRowToolTip]).Value = null;
                ((DynaCommand)this.dgSort.Resources[DATASORT_elementSwitchFieldsComboOrderByCmd]).Value = null;
                ((DynaObject )this.dgSort.Resources[DATASORT_elementSwitchFieldsComboOrderByToolTip]).Value = null;
                ((DynaObject )this.dgSort.Resources[DATASORT_elementFieldsComboOrderByImage]).Value = null;
                ((DynaString )this.dgSort.Resources[DATASORT_elementDataGridColumnSortPropertyPathHeader]).Value = null;
            }

            this.dgSort = GetTemplateChild(DATASORT_elementDataGridSort) as DataGrid;

            if (this.dgSort != null)
            {
                this.dgSort.DataGridRefreshItemsSource(this.dataGridSortItems);
                this.dgSort.PreparingCellForEdit += OnDataGridSortPreparingCellForEdit;
                this.dgSort.SelectionChanged     += dgSort_SelectionChanged;
                this.dgSort.CurrentCellChanged   += dgSort_CurrentCellChanged;
                ((DynaCommand)this.dgSort.Resources[DATASORT_elementDeleteRowCmd]).Value = deleteRowCmd;
                ((DynaObject )this.dgSort.Resources[DATASORT_elementDeleteRowToolTip]).Value = this.ButtonDeleteSortTooltip;
                ((DynaCommand)this.dgSort.Resources[DATASORT_elementSwitchFieldsComboOrderByCmd]).Value = switchFieldsComboOrderByCmd;
                ((DynaObject )this.dgSort.Resources[DATASORT_elementSwitchFieldsComboOrderByToolTip]).Value = this.ButtonSwitchFieldsComboOrderByTooltip;
                SetFieldsComboOrderByImage();
                ((DynaString )this.dgSort.Resources[DATASORT_elementDataGridColumnSortPropertyPathHeader]).Value = this.SortPropertyPathHeader;
            }

            #endregion
        }

        void dgSort_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
          deleteCmd.CanExecute(null);
          deleteRowCmd.CanExecute(null);
        }

        void dgSort_CurrentCellChanged(object sender, EventArgs e)
        {
          dgSort.BeginEdit();
        }

        #endregion

        #region Private Methods

        #region Private Method RefreshListOfDomainEntityFields

        private void RefreshListOfDomainEntityFields()
        {
          if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this) && this.DomainDataSource != null)
          {
            var fields = Utilities.GetListOfDomainEntityFields(this.DomainDataSource, Utilities.ParseStringAsListOfString(this.IncludeFieldList), Utilities.ParseStringAsListOfString(this.ExcludeFieldList), this.DomainEntityFieldCollection);
            switch (EntityFieldsComboOrderBy) {
              case EntityFieldsOrder.Alphabetical: fields = fields.OrderBy(r => r.DisplayName).ToList(); break;
              case EntityFieldsOrder.DisplayOrder: fields = fields.OrderBy(r => r.OrderId    ).ToList(); break;
            }
            this.ListOfDomainEntityFields = fields;
          }
        }

        #endregion

        #region Private Method OnDataSortLayoutUpdated

        private void OnDataSortLayoutUpdated(object sender, EventArgs e)
        {
          if (this.ListOfDomainEntityFields == null)
            RefreshListOfDomainEntityFields();
        }

        #endregion

        #region Private Method RefreshCommands

        private void RefreshCommands()
        {
          this.applyCmd.CanExecute(null);
          this.cancelCmd.CanExecute(null);
          this.deleteCmd.CanExecute(null);
          this.clearCmd.CanExecute(null);
          this.deleteRowCmd.CanExecute(null);
        }

        #endregion

        #region Private Method RefreshControls

        private void RefreshControls()
        {
          this.dgSort.DataGridRefreshItemsSource(this.dataGridSortItems);
          RefreshCommands();
        }

        #endregion

        #region Private Method OnButtonAddSortClick

        /// <summary>
        /// Handles the click of the AddSort button.
        /// </summary>
        /// <param name="sender">The button.</param>
        /// <param name="e">The event args.</param>
        private void OnButtonAddSortClick(object sender, RoutedEventArgs e)
        {
            this.AddSortItem();
        }

        #endregion

        #region Private Method OnDataGridSortPreparingCellForEdit

        /// <summary>
        ///
        /// </summary>
        /// <param name="sender">DataGrid</param>
        /// <param name="e">DataGridPreparingCellForEditEventArgs</param>
        private void OnDataGridSortPreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e)
        {
            DataGridSortItem dgSelectedItem = (this.dgSort.SelectedItem as DataGridSortItem);
            FrameworkElement editingElement = e.EditingElement;

            if (editingElement == null)
            {
                return;
            }

            string columnName = e.Column.GetValue(FrameworkElement.NameProperty) as string;

            if (string.IsNullOrWhiteSpace(columnName))
            {
                return;
            }

            bool processed = false;
            switch (columnName)
            {
                //Initialized dgcSortPropertyPath DataGridTemplateColumn.CellEditingTemplate
                case DATASORT_elementDataGridColumnSortPropertyPath:
                    if (e.EditingElement.GetType() == typeof(ComboBox))
                    {
                        ComboBox element = e.EditingElement as ComboBox;

                        if (element == null)
                        {
                            return;
                        }

                        element.SelectionChanged -= OnSortPropertyPathComboBoxSelectionChanged;
                        element.DisplayMemberPath = "DisplayName";
                        element.ItemsSource = this.ListOfDomainEntityFields;
                        if (this.dgSort.SelectedItem != null)
                        {
                            element.SelectedItem = this.ListOfDomainEntityFields.FirstOrDefault(r => r.PropertyPath == (this.dgSort.SelectedItem as DataGridSortItem).SortDescriptor.PropertyPath);
                        }
                        element.SelectionChanged += OnSortPropertyPathComboBoxSelectionChanged;
                        processed = true;
                    }
                    break;

                //Initialized dgcSortDirection DataGridTemplateColumn.CellEditingTemplate
                case DATASORT_elementDataGridColumnSortDirection:
                    if (e.EditingElement.GetType() == typeof(ComboBox))
                    {
                        ComboBox element = e.EditingElement as ComboBox;

                        if (element == null)
                        {
                            return;
                        }

                        element.SelectionChanged -= OnSortDirectionComboBoxSelectionChanged;
                        element.ItemsSource = this.ListOfSortDirectionNames;
                        if (this.dgSort.SelectedItem != null)
                        {
                            element.SelectedItem = this.ListOfSortDirectionNames.FirstOrDefault(r => r == Utilities.GetLocalizationBySortDirection(dgSelectedItem.SortDescriptor.Direction, this.SortDirectionLocalizationCollection));
                        }
                        element.SelectionChanged += OnSortDirectionComboBoxSelectionChanged;
                        processed = true;
                    }
                    break;
            }

            if (!processed) {
              if (editingElement is TextBox) {
                (editingElement as TextBox).TextChanged -= DataGridSort_CellTextChanged;
                (editingElement as TextBox).TextChanged += DataGridSort_CellTextChanged;
                processCellChanges(editingElement);
              }
              else if (editingElement is CheckBox) {
                (editingElement as CheckBox).Click -= DataGridSort_CellCheckBoxClick;
                (editingElement as CheckBox).Click += DataGridSort_CellCheckBoxClick;
                processCellChanges(editingElement);
              }
            }

            if (CellEditorPrepared != null)
              CellEditorPrepared(editingElement, null);
        }

        void processCellChanges(object ed)
        {
          if (ed is CheckBox) {
            var be = (ed as CheckBox).GetBindingExpression(CheckBox.IsCheckedProperty);
            if (be != null) be.UpdateSource();
            RefreshCommands();
          }
          else if (ed is TextBox) {
            var be = (ed as TextBox).GetBindingExpression(TextBox.TextProperty);
            if (be != null) be.UpdateSource();
            RefreshCommands();
          }
        }

        void DataGridSort_CellCheckBoxClick(object sender, RoutedEventArgs e)
        {
          processCellChanges(sender);
        }

        void DataGridSort_CellTextChanged(object sender, TextChangedEventArgs e)
        {
          processCellChanges(sender);
        }

        #endregion

        #region Private Method OnSortPropertyPathSelectionChanged

        /// <summary>
        ///
        /// </summary>
        /// <param name="sender">ComboBox</param>
        /// <param name="e">SelectionChangedEventArgs</param>
        private void OnSortPropertyPathComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            DomainEntityField result = ((ComboBox)sender).SelectedItem as DomainEntityField;
            if (this.dataGridSortItems == null ||
                this.dataGridSortItems.Count == 0 ||
                this.dgSort.SelectedItem == null ||
                result == null)
            {
                return;
            }

            DataGridSortItem record = (this.dgSort.SelectedItem as DataGridSortItem);
            record.SortDescriptor.PropertyPath = result.PropertyPath;
            RefreshCommands();
        }

        #endregion

        #region Private Method OnSortDirectionComboBoxSelectionChanged

        /// <summary>
        ///
        /// </summary>
        /// <param name="sender">ComboBox</param>
        /// <param name="e">SelectionChangedEventArgs</param>
        private void OnSortDirectionComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            string result = ((ComboBox)sender).SelectedItem as string;

            if (this.dataGridSortItems == null ||
                this.dataGridSortItems.Count == 0 ||
                this.dgSort.SelectedItem == null ||
                result == null)
            {
                return;
            }

            DataGridSortItem record = (this.dgSort.SelectedItem as DataGridSortItem);
            record.SortDescriptor.Direction = Utilities.GetSortDescriptorByLocalization(result, this.SortDirectionLocalizationCollection);
            RefreshCommands();
        }

        #endregion

        #region Private Method AddSortItem

        /// <summary>
        ///
        /// </summary>
        /// <returns>bool</returns>
        private bool AddSortItem()
        {
            if (this.dataGridSortItems == null ||
                this.ListOfDomainEntityFields == null ||
                this.ListOfDomainEntityFields.Count == 0)
            {
                return false;
            }

            this.dataGridSortItems.Add(
                new DataGridSortItem(this.ListOfDomainEntityFields)
                {
                    SortDescriptor = new SortDescriptor(this.ListOfDomainEntityFields[0].PropertyPath, Utilities.GetSortDescriptorByLocalization(this.ListOfSortDirectionNames[0], this.SortDirectionLocalizationCollection))
                });
            this.RefreshControls();

            return true;
        }

        #endregion

        #region Private Method DeleteSortItem

        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        private void DeleteSortItem(object param = null)
        {
            if (this.dataGridSortItems == null ||
                this.dataGridSortItems.Count == 0 ||
                this.dgSort.SelectedItem == null)
            {
                return;
            }

            if (dgSort.SelectedItems.Count > 1) {
              var lst = new List<object>();
              foreach (var i in dgSort.SelectedItems) lst.Add(i);
              foreach (var j in lst) this.dataGridSortItems.Remove((DataGridSortItem)j);
            }
            else this.dataGridSortItems.Remove((DataGridSortItem)this.dgSort.SelectedItem);

            this.RefreshControls();
        }

        private bool CanDeleteSortItem(object param)
        {
          return this.dataGridSortItems != null && this.dataGridSortItems.Count > 0 &&
                 this.dgSort != null && this.dgSort.SelectedItem != null;
        }

        #endregion

        #region Private Method DeleteRowSortItem

        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        private void DeleteRowSortItem(object param = null)
        {
          if (this.dataGridSortItems == null ||
              this.dataGridSortItems.Count == 0 ||
              this.dgSort.SelectedItem == null || dgSort.SelectedItems.Count != 1)
          {
            return;
          }

          this.dataGridSortItems.Remove((DataGridSortItem)this.dgSort.SelectedItem);
          this.RefreshControls();
        }

        private void AsyncDeleteRowSortItem(object param)
        {
          // in grid DeleteRowBtn defines ClickMode="Press", that's why we cannot delete right away, UI is not "stable" yet and must finish its work
          // also SelectedItem won't be changed as it happens in ClickMode="Release", so we must do it manually

          DataGridSortItem rowItem = null;
          if (param is FrameworkElement && ((FrameworkElement)param).DataContext is DataGridSortItem)
            rowItem = ((FrameworkElement)param).DataContext as DataGridSortItem;

          this.Dispatcher.BeginInvoke(delegate {
            if (rowItem != null) dgSort.SelectedItem = rowItem;
            DeleteRowSortItem(param);
          });
        }

        private bool CanDeleteRowSortItem(object param)
        {
          return this.dataGridSortItems != null && this.dataGridSortItems.Count > 0 &&
                 this.dgSort != null && this.dgSort.SelectedItem != null && dgSort.SelectedItems.Count == 1;
        }

        #endregion

        #region Private Method ClearSortItem

        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        private void ClearSortItem(object param = null)
        {
            if (this.dataGridSortItems == null ||
                this.dataGridSortItems.Count == 0)
            {
                return;
            }

            while (this.dataGridSortItems.Count > 0)
            {
                this.dataGridSortItems.RemoveAt(0);
            }

            this.RefreshControls();
        }

        private bool CanClearSortItem(object param)
        {
          return this.dataGridSortItems != null && this.dataGridSortItems.Count > 0;
        }

        #endregion

        #region Private Method SwitchFieldsComboOrderBy

        /// <summary>
        /// Delete selected filter item from list.
        /// </summary>
        private void SwitchFieldsComboOrderBy(object param)
        {
          switch (EntityFieldsComboOrderBy) {
            case EntityFieldsOrder.Alphabetical:
              dgSort.CommitEdit();
              EntityFieldsComboOrderBy = EntityFieldsOrder.DisplayOrder;
              break;
            case EntityFieldsOrder.DisplayOrder:
              dgSort.CommitEdit();
              EntityFieldsComboOrderBy = EntityFieldsOrder.Alphabetical;
              break;
          }
        }

        private bool CanSwitchFieldsComboOrderBy(object param)
        {
          return (EntityFieldsComboOrderBy == EntityFieldsOrder.Alphabetical ||
                  EntityFieldsComboOrderBy == EntityFieldsOrder.DisplayOrder);
        }

        #endregion

        #endregion

        #region Public Methods

        #region Private Method ApplyFilters

        /// <summary>
        /// Apply and add sort items to the DomainDataSource.
        /// </summary>
        public void ApplyFilters(object param = null)
        {
            if (this.OnApplyButtonBeforeClick != null)
            {
                this.OnApplyButtonBeforeClick(this, null);
            }

            if (this.DomainDataSource != null)
            {
                changingSortDescrs = true;
                try {
                  this.DomainDataSource.IsEnabled = false;
                  this.DomainDataSource.SetToDDSSortDescriptorsCopy(this.dataGridSortItems);
                  this.DomainDataSource.IsEnabled = true;
                }
                finally {
                  changingSortDescrs = false;
                };
            }

            if (this.OnApplyButtonAfterClick != null)
            {
                this.OnApplyButtonAfterClick(this, null);
                // rereading from the current state of dds (in case SortDescriptors were postprocessed by OnApplyButtonAfterClick)
                if (this.DomainDataSource != null && !ListenSortDescriptorsChanges)
                {
                  this.DomainDataSource.IsEnabled = false;
                  this.DomainDataSource.GetDDSSortDescriptorsCopy(this.ListOfDomainEntityFields, this.dataGridSortItems);
                  this.DomainDataSource.IsEnabled = true;
                  RefreshControls();
                  return;
                }
            }

            if (this.DomainDataSource != null) {
              this.applyCmd.CanExecute(null);
              this.cancelCmd.CanExecute(null);
            }
        }

        public bool CanApplyFilters(object param)
        {
          if (this.DomainDataSource != null)
            return !this.DomainDataSource.DDSSortDescriptorsEqual(this.dataGridSortItems);
          else
            return false;
        }

        #endregion

        #region Private Method CancelFilters

        /// <summary>
        /// Cancel add sort intems to the DomainDataSource.
        /// </summary>
        public void CancelFilters(object param = null)
        {
            if (this.OnCancelButtonBeforeClick != null)
            {
                this.OnCancelButtonBeforeClick(this, null);
            }

            if (this.DomainDataSource != null)
            {
                this.DomainDataSource.IsEnabled = false;
                this.DomainDataSource.GetDDSSortDescriptorsCopy(this.ListOfDomainEntityFields, this.dataGridSortItems);
                this.DomainDataSource.IsEnabled = true;
            }

            if (this.OnCancelButtonAfterClick != null)
            {
                changingSortDescrs = true;
                try {
                  this.OnCancelButtonAfterClick(this, null);
                }
                finally {
                  changingSortDescrs = false;
                }
            }

            if (this.DomainDataSource != null)
              RefreshControls(); // Apply-Clear-Cancel scenario, UI must be refreshed
        }

        public bool CanCancelFilters(object param)
        {
          if (this.DomainDataSource != null) {
            if (this.OnCanCancel != null) return OnCanCancel(this, null);
                                     else return this.DomainDataSource.SortDescriptors.Count > 0;
          }
          else return false;
        }

        #endregion

        #endregion
    }
}
